﻿using UnityEngine;
using System.Collections;
using System;

public class BMath
{
    /// <summary>
    /// 获取贝塞尔曲线上的点
    /// </summary>
    public static Vector3 GetBezierPoint(Vector3 p1, Vector3 p2, Vector3 p3, float t)
    {
        //t范围0到1,对应的贝塞尔起点到终点;
        float x = CalculateQuadSpline(p1.x, p2.x, p3.x, t);
        float y = CalculateQuadSpline(p1.y, p2.y, p3.y, t);
        float z = CalculateQuadSpline(p1.z, p2.z, p3.z, t);
        return new Vector3(x, y, z);
    }
    /// <summary>
    /// 获取贝塞尔曲线上的点
    /// </summary>
    public static Vector2 GetBezierPoint(Vector2 p1, Vector2 p2, Vector2 p3, float t)
    {
        //t范围0到1,对应的贝塞尔起点到终点;
        float x = CalculateQuadSpline(p1.x, p2.x, p3.x, t);
        float y = CalculateQuadSpline(p1.y, p2.y, p3.y, t);
        return new Vector2(x, y);
    }
    /// <summary>
    /// 获取贝塞尔曲线上所有的点
    /// </summary>
    public static Vector3[] GetBezierPoints(Vector3 p1, Vector3 p2, Vector3 p3, int pointsAmount)
    {
        int amount = pointsAmount - 1;
        Vector3[] newVector2 = new Vector3[pointsAmount];
        float tStep = 1 / ((float)amount);
        float t = 0f;
        for (int ik = 0; ik <= amount; ik++)
        {
            float x = CalculateQuadSpline(p1.x, p2.x, p3.x, t);
            float y = CalculateQuadSpline(p1.y, p2.y, p3.y, t);
            float z = CalculateQuadSpline(p1.z, p2.z, p3.z, t);
            newVector2[ik] = new Vector3(x, y, z);
            t = t + tStep;
        }
        newVector2[amount] = p3;
        return newVector2;
    }
    /// <summary>
    /// 获取贝塞尔曲线上所有的点
    /// </summary>
    public static Vector2[] GetBezierPoints(Vector2 p1, Vector2 p2, Vector2 p3, int pointsAmount)
    {
        int amount = pointsAmount - 1;
        Vector2[] newVector2 = new Vector2[pointsAmount];
        float tStep = 1 / ((float)amount);
        float t = 0f;
        for (int ik = 0; ik <= amount; ik++)
        {
            float x = CalculateQuadSpline(p1.x, p2.x, p3.x, t);
            float y = CalculateQuadSpline(p1.y, p2.y, p3.y, t);
            newVector2[ik] = new Vector2(x, y);
            t = t + tStep;
        }
        newVector2[amount] = p3;
        return newVector2;
    }
    static float CalculateQuadSpline(float z0, float z1, float z2, float t)
    {
        float a1 = (float)((1.0 - t) * (1.0 - t) * z0);
        float a2 = (float)(2.0 * t * (1 - t) * z1);
        float a3 = (float)(t * t * z2);
        float a4 = a1 + a2 + a3;
        return a4;
    }

    /// <summary>
    /// 绕任意轴任意角度旋转向量 
    /// </summary>
    public static Vector3 RotateRound(Vector3 position, Vector3 center, Vector3 axis, float angle)
    {
        Vector3 point = Quaternion.AngleAxis(angle, axis) * (position - center);
        Vector3 resultVec3 = center + point;
        return resultVec3;
    }

    /// <summary>
    /// 直线方程
    /// </summary>
    public class Line
    {
        public float k, b;
        public Vector2 p1, p2;
        public float radian;
        public Line(Vector2 point1, Vector2 point2) : this(point1.x, point1.y, point2.x, point2.y) { }
        public Line(float x1, float y1, float x2, float y2)
        {
            this.p1 = new Vector2(x1, y1);
            this.p2 = new Vector2(x2, y2);
            k = (y2 - y1) / (x2 - x1);
            b = y1 - k * x1;
            radian = Mathf.Atan2(y2 - y1, x2 - x1);
        }
        public Line(Vector2 point1, float radian)
        {
            this.p1 = point1;
            this.p2.x = this.p1.x + Mathf.Cos(radian);
            this.p2.y = this.p1.y + Mathf.Sin(radian);
            k = (p2.y - point1.y) / (p2.x - point1.x);
            b = point1.y - k * point1.x;
            this.radian = radian;
        }
        public float GetX(float y)
        {
            return (y - b) / k;
        }
        public float GetY(float x)
        {
            return k * x + b;
        }
    }

    /// <summary>
    /// 获取二维平面两条直线的交点
    /// </summary>
    public static Vector2 GetCrossPointOf2Line(Line line1, Line line2)
    {
        return GetCrossPointOf2Line(line1.p1, line1.p2, line2.p1, line2.p2);
    }

    public static Vector2 GetCrossPointOf2Line(Vector2 a1, Vector2 a2, Vector2 b1, Vector2 b2)
    {
        float a = 0, b = 0;
        int state = 0;
        if (a1.x != a2.x)
        {
            a = (a2.y - a1.y) / (a2.x - a1.x);
            state |= 1;
        }
        if (b1.x != b2.x)
        {
            b = (b2.y - b1.y) / (b2.x - b1.x);
            state |= 2;
        }
        switch (state)
        {
            case 0://L1与L2都平行Y轴
                {
                    if (a1.x == b1.x)
                    {
                        return new Vector2(0, 0);
                    }
                    else
                    {
                        return new Vector2(0, 0);
                    }
                }
            case 1://L1存在斜率, L2平行Y轴
                {
                    float x = b1.x;
                    float y = (a1.x - x) * (-a) + a1.y;
                    return new Vector2(x, y);
                }
            case 2://L1平行Y轴，L2存在斜率
                {
                    float x = a1.x;
                    float y = (b1.x - x) * (-b) + b1.y;
                    return new Vector2(x, y);
                }
            case 3://L1，L2都存在斜率
                {
                    if (a == b)
                    {
                        return new Vector2(0, 0);
                    }
                    float x = (a * a1.x - b * b1.x - a1.y + b1.y) / (a - b);
                    float y = a * x - a * a1.x + a1.y;
                    return new Vector2(x, y);
                }
        }
        return new Vector2(0, 0);
    }

    /// <summary>
    /// 获取三维空间两条直线的交点
    /// </summary>
    public static Vector3 GetCrossPoint(Vector3 p1, Vector3 v1, Vector3 p2, Vector3 v2)
    {
        if (Vector3.Dot(v1, v2) == 1)
        {
            Debug.LogError("两线平行");
            return Vector3.zero;
        }
        Vector3 startPointSeg = p2 - p1;
        Vector3 vecS1 = Vector3.Cross(v1, v2);
        Vector3 vecS2 = Vector3.Cross(startPointSeg, v2);
        float num = Vector3.Dot(startPointSeg, vecS1);
        if (num >= 1E-05f || num <= -1E-05f)
        {
            Debug.LogError("四点不共面");
            return Vector3.zero;
        }
        float num2 = Vector3.Dot(vecS2, vecS1) / vecS1.sqrMagnitude;
        return p1 + v1 * num2;
    }

    /// <summary>
    /// 获取两点连线的中点
    /// </summary>
    public static Vector2 GetCenterBetween2Points(Vector2 point1, Vector2 point2)
    {
        return new Vector2((point1.x + point2.x) * 0.5f, (point1.y + point2.y) * 0.5f);
    }

    /// <summary>
    /// 按小数点后几位向下取,不足用0补齐
    /// </summary>
    public static string Floor(double value, int decimals = 2)
    {
        if (decimals <= 0)
        {
            string resultStr = value.ToString();
            int dotIndex = resultStr.IndexOf(".");
            if (dotIndex > 0)
            {
                return resultStr.Substring(0, dotIndex);
            }
            return resultStr;
        }
        else
        {
            string resultStr = value.ToString("F" + (decimals + 1));
            return resultStr.Substring(0, resultStr.Length - 1);
        }
    }

    //获取两个角的夹角(锐角)
    public static float GetIncAngle(float angle1, float angle2)
    {
        float angle = Mathf.Abs(Angle360(angle1) - Angle360(angle2));
        if (angle > 180) angle = 360 - angle;
        return angle;
    }

    //将角度转为0-360度的值
    public static float Angle360(float angle)
    {
        while (angle < 0)
        {
            angle += 360;
        }
        while (angle > 360)
        {
            angle -= 360;
        }
        return angle;
    }

    //点到线段(非直线)的最小距离(此处未开方，开方即可得到真正的距离，不开方与外部值的平方做比较能大幅提高运算效率)
    public static float GetDistance(Vector2 p, Vector2 a, Vector2 b)
    {
        //平移到p为原点
        a.x -= p.x;
        a.y -= p.y;
        b.x -= p.x;
        b.y -= p.y;
        //线段ab到远点的距离
        float r = (a.x - b.x) * (a.x) + (a.y - b.y) * a.y;
        float d = (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
        if (r <= 0) return a.x * a.x + a.y * a.y;
        else if (r >= d) return b.x * b.x + b.y * b.y;
        r /= d;
        float x = a.x + (b.x - a.x) * r, y = a.y + (b.y - a.y) * r;
        return x * x + y * y;
    }

    //判断一点是否在另外两点内测
    public static bool IsInside(Vector2 p, Vector2 a, Vector2 b)
    {
        Vector2 ab = b - a, ap = p - a;
        Vector2 ba = a - b, bp = p - b;
        return Vector2.Dot(ab, ap) > 0 && Vector2.Dot(ba, bp) > 0;
    }

    //求平面内点到直线的垂足
    public static Vector2 GetFootPoint(Vector2 p, Vector2 a, Vector2 b)
    {
        Vector2 d = a - b;
        float u = (p.x - a.x) * (a.x - b.x) + (p.y - a.y) * (a.y - b.y);
        u = u / ((d.x * d.x) + (d.y * d.y));
        return new Vector2(a.x + u * d.x, a.y + u * d.y);
    }

    //判断一点是否在一个不规则多边形内部
    public static bool IsInPolygon(Vector2 point, Vector2[] polygonPoints)
    {
        bool inside = false;
        int pointCount = polygonPoints.Length;
        Vector2 p1, p2;
        for (int i = 0, j = pointCount - 1; i < pointCount; j = i, i++)
        {
            p1 = polygonPoints[i];
            p2 = polygonPoints[j];
            if (point.y < p2.y)
            {
                if (p1.y <= point.y)
                {
                    if ((point.y - p1.y) * (p2.x - p1.x) > (point.x - p1.x) * (p2.y - p1.y))
                    {
                        inside = (!inside);
                    }
                }
            }
            else if (point.y < p1.y)
            {
                if ((point.y - p1.y) * (p2.x - p1.x) < (point.x - p1.x) * (p2.y - p1.y))
                {
                    inside = (!inside);
                }
            }
        }
        return inside;
    }
}